use anyhow::Result;
use std::io::ErrorKind;
use std::net::SocketAddr;
use tokio::io::AsyncWriteExt;
use tracing::{info, warn};

const BUF_SIZE: usize = 4096;

#[tokio::main]
async fn main() -> Result<()> {
    println!("hello world");
    tracing_subscriber::fmt::init();

    //build a listener
    let addr = "0.0.0.0:6380";
    let listener = tokio::net::TcpListener::bind(addr).await?;
    info!("Dredis: listening on {addr}");

    loop {
        let (stream, raddr) = listener.accept().await?;
        info!("Dredis: accepted connection from {raddr}");
        tokio::spawn(async move {
            if let Err(e) = process_redis_connection(stream, raddr).await {
                warn!("Dredis: connection {raddr} error:{e:?}");
            }
        });
    }
    #[allow(unreachable_code)]
    Ok(())
}
async fn process_redis_connection(
    mut stream: tokio::net::TcpStream,
    raddr: SocketAddr,
) -> Result<()> {
    loop {
        stream.readable().await?;
        let mut buf = Vec::with_capacity(BUF_SIZE);
        match stream.try_read_buf(&mut buf) {
            Ok(0) => {
                info!("Dredis: connection closed");
                break;
            }
            Ok(n) => {
                info!("Dredis: received {n} bytes");
                let line = String::from_utf8_lossy(&buf);
                info!("{line:?}");
                stream.write_all(b"+OK\r\n").await?;
            }
            Err(e) if e.kind() == ErrorKind::WouldBlock => {
                continue;
            }
            Err(e) => {
                return Err(e.into());
            }
        }
    }
    warn!("Dredis: connection {raddr} closed");
    Ok(())

    // let (reader,writer) = stream.into_split();
    // let mut reader = tokio::io::BufReader::new(reader);
    // let mut writer = tokio::io::BufWriter::new(writer);
    // loop{
    //     let mut buf = vec![0u8; 64];
    //     let n = reader.read(&mut buf).await.unwrap();
    //     if n == 0 {
    //         break;
    //     }
    //     let cmd = String::from_utf8_lossy(&buf);
    //     info!("Dredis: received command {cmd:?}");
    //     writer.write_all(&buf[..n]).await.unwrap();
    //     writer.flush().await.unwrap();
    //
    // }
}
